package org.myframework.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
 * Sign 签名生成方法：对数据里面的内容进行鉴权，确定携带的信息是真实、有效、合理的。
 * <ol>
 * <li>{@link MD5Util }</li>
 *
 * </ol>
 * @see
 * @author wanghui
 * @since 1.0
 * @2015年1月27日
 *
 */
public class ParamSignUtil {
	private static Logger logger = LoggerFactory.getLogger(ParamSignUtil.class);
	/**
	 *  1.对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）后，使用 URL 键值对的
	 *	格式（即 key1=value1&key2=value2…）拼接成字符串 str1，注意：值为空的参数不参加签名
	 *
	 *	2.在 str1 最后拼接上 key=CLIENT_SECRET( 第三方应用接入密钥) 得到 stringSignTemp 字符串，幵对
	 *	stringSignTemp 进行 md5 运算，再将得到的字符串所有字符转换为大写，得到 sign 值signValue
	 *
	 *  注意：
	 *  第一步中的传入参数 是服务端通过request.getParameterMap()方式获取的；
	 *  第二步中的CLIENT_SECRET是服务端根据client_id查询数据库获得，不需要由客户端传输。
	 * @param params
	 * client_id:接入应用的APP_ID
	 * nonce_str:随机字符串，作用是提高签名破解的复杂度
	 * sign:客户端提交的数字签名，需要根据服务端要求的方式进行签名，否则请求提交失败
	 * @param client_secret
	 * @return
	 */
	public static String paramSign(Map<String, String> params,
			String client_secret) {
		//必备参数验证
		Assert.notNull(client_secret , "client_secret不可为空!");
		Assert.isTrue(params.containsKey("client_id"), "参数client_id不存在!");
		Assert.isTrue(params.containsKey("nonce_str"), "参数nonce_str不存在!");
		Assert.isTrue(params.containsKey("sign"), "参数sign不存在!");

		//1.按参数名字母排序
		SortedMap<String, String> sortParams = new TreeMap<String, String>(
				params);
		List<String> paramList = new ArrayList<String>(4);
		for (String paramKey : sortParams.keySet()) {
			String value = sortParams.get(paramKey);
			if ("sign".equals(paramKey)||!StringUtils.hasLength(value)) {
				continue;
			}
			paramList.add(paramKey + "=" + value);
		}

		String str1 = StringUtils.collectionToDelimitedString(paramList, "&");
		String stringSignTemp = str1 + "&key=" + client_secret ;
		String signStr = MD5Util.toMD5(stringSignTemp).toUpperCase();
		logger.info("stringSignTemp : " + stringSignTemp);
		logger.info("signStr : " + signStr);
		logger.info("client_sign :" +params.get("sign"));
		logger.info("server_sign :" + signStr);
		return signStr;
	}

	public static void main(String[] args) {
		//?client_id=1&nonce_str=2&name=wanghui&sign=118FAE1CBED859FD63C2C1E09E3AB269
		// ==================================获取客户端请求参数==============================
		String client_id = "1";
		Map<String, String> params = new HashMap<String, String>();
		params.put("client_id", client_id);
		params.put("nonce_str", "2");
		params.put("sign", "4A5E97E47A9B596D19A701C6F765219C");
		params.put("name", "wanghui");
		//params.put("order", "3");

		// ==================================服务端签名验证过程==============================
		// 请求参数中携带的数字签名
		String sign0 = params.get("sign");
		System.out.println(sign0);
		// 根据约定算法正确的签名
		String client_secret = "1";
		String sign1 = ParamSignUtil.paramSign(params, client_secret);
		System.out.println(sign1);
		// 比对签名信息
		if (sign0.equals(sign1)) {
			System.out.println("合法参数请求");
		}
	}


}
